#ifndef U1_CORATINGS_H_
#define U1_CORATINGS_H_

#include "io.h"

template <typename rating_t>
bool is_movie(id_rating_t<rating_t> *r, size_t i) { return is_block(r, i); }

/* Iterate over coratings of movies i and j where i <= j. The handler is a
 * generalized functor; it must provide methods begin_pair, corating and
 * end_pair as follows. They are called as the iteration proceeds.
 *
 * begin_pair(int id_i, int id_j);
 * corating(int id, float rating_i, float rating_j);
 * end_pair();
 */
template <typename rating_t, typename F_handler>
void for_coratings(id_rating_t<rating_t> *r, size_t n, F_handler &handler) {

  // List must now begin and end with movie.
  assert(is_movie(r, 0) && is_movie(r, n-1));

  // Make a pass to check that our sorting invariants are satisfied.
  assert_r_ordered(r, n);

  size_t i_movie = 0;
  do {
    // Coratings are symmetric, so we need consider only those on (say) the
    // lower diagonal, where i <= j.
    size_t j = i_movie;
    do {
      handler.begin_pair(r[i_movie].id, r[j].id);

      // Reset i to first rating for movie i.
      // Advance j to the first rating for movie j.
      size_t i = i_movie + 1;
             j = j + 1;

      // Proceed until we run out of ratings for one of the movies.
      while (!is_movie(r, i) && !is_movie(r, j)) {
        // We have that ratings are sorted by movie.
        if (r[i].id < r[j].id) {
          ++i;
        } else if (r[i].id > r[j].id) {
          ++j;
        } else {
          handler.corating(r[i].id, r[i].rating, r[j].rating);
          ++i;
          ++j;
        }
      }

      // Find next movie record j.
      while (!is_movie(r, j))
        ++j;

      handler.end_pair();
    } while (r[j].id != BAD_ID);

    // Find start of next movie.
    do ++i_movie; while (!is_movie(r, i_movie));

#ifndef NDEBUG
    // Tracing.
    if (r[i_movie].id % 100 == 0)
      TRACE<<"now on movie "<<r[i_movie].id<<std::endl;
#endif

  } while(r[i_movie].id != BAD_ID);
}

#endif // guard
/*
* Copyright (c) 2009 John Lees-Miller
* 
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
* 
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/

